package com.aaa.sentinel;

import com.alibaba.cloud.sentinel.feign.SentinelInvocationHandler;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

@Component
public class SentinelConfig {
    private final List<ViewResolver> viewResolvers;

    private final ServerCodecConfigurer serverCodecConfigurer;

    // 构造方法
    public SentinelConfig(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }


    //启用sentinel过滤器
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE-1)
    public GlobalFilter sentinelGolbalFilter(){
        return new SentinelGatewayFilter();
    }

    //启用sentinel注解配置
    @Bean
    public SentinelResourceAspect sentinelResourceAspect(){
        return new SentinelResourceAspect();
    }
    //定义流控规则
    //PostConstruct构造方法加载之后执行,对象创建完成立刻加载
    @PostConstruct
    public void initFlowRules(){
        //new ParamFlowRule();热点
        GatewayFlowRule bookservice = new GatewayFlowRule("bookservice");
        bookservice.setGrade(0);//类型
        bookservice.setCount(5);//单机阈值
        bookservice.setIntervalSec(1);//统计时间间隔

        GatewayFlowRule orderservice = new GatewayFlowRule("orderservice");
        orderservice.setGrade(0);//类型
        orderservice.setCount(5);//单机阈值
        orderservice.setIntervalSec(1);//统计时间间隔

        HashSet<GatewayFlowRule> set = new HashSet<>();
        set.add(bookservice);
        set.add(orderservice);

        //加载熔断规则
        GatewayRuleManager.loadRules(set);
    }

    //流控异常处理
    @Bean
    public SentinelGatewayBlockExceptionHandler blockHandler(){
        return new SentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);
    }

    //返回视图
    @PostConstruct
    public void setViewResolvers(){
        BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                HashMap<Object, Object> map = new HashMap<>();
                map.put("code",100);
                map.put("msg","请求过多,请等待");

                //状态码:200,响应类型:json,响应内容map
                return  ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(map));

            }
        };
        //设置网关的回调处理
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }
}
